/*  
 * Actipro Software's WPF Docking & MDI / Prism Integration Add-on
 * http://actipro.codeplex.com/
 * 
 * Copyright (c) 2009-2015 Actipro Software LLC. 
 *  
 * This source code is subject to the terms of the Microsoft Public License (Ms-PL). 
 *  
 * Redistribution and use in source and binary forms, with or without modification, 
 * is permitted provided that redistributions of the source code retain the above 
 * copyright notices and this file header. 
 *  
 * Additional copyright notices should be appended to the list above. 
 * 
 * For details, see <http://www.opensource.org/licenses/ms-pl.html>. 
 *  
 * All other rights reserved. 
 *
 */  

using System;
using System.ComponentModel;
using System.ComponentModel.Design.Serialization;
using System.Globalization;
using System.Reflection;
using System.Security;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Media;

namespace ActiproSoftware.Products.Docking.Interop.Prism {

	/// <summary>
	/// Provides a markup extension for loading a string resource from the assembly that could possibly be customized.
	/// </summary>
	[
		MarkupExtensionReturnType(typeof(string)), 
		TypeConverter(typeof(SRExtensionConverter))
	]
	public class SRExtension : MarkupExtension {

		private string name;
		
		/////////////////////////////////////////////////////////////////////////////////////////////////////
		// NESTED TYPES
		/////////////////////////////////////////////////////////////////////////////////////////////////////

		#region SRExtensionConverter

		/// <summary>
		/// Provides a <c>TypeConverter</c> to convert <see cref="SRExtension"/> objects to and from other representations.
		/// </summary>
		internal class SRExtensionConverter : TypeConverter {

			/// <summary>
			/// Returns whether this converter can convert the object to the specified type, using the specified context.
			/// </summary>
			/// <param name="context">An <c>ITypeDescriptorContext</c> that provides a format context.</param>
			/// <param name="destinationType">A <c>Type</c> that represents the type you want to convert to.</param>
			/// <returns><c>true</c> if this converter can perform the conversion; otherwise, <c>false</c>.</returns>
			public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
				return ((destinationType == typeof(InstanceDescriptor)) || base.CanConvertTo(context, destinationType));
			}

			/// <summary>
			/// Converts the given value object to the specified type, using the specified context and culture information.
			/// </summary>
			/// <param name="context">An <c>ITypeDescriptorContext</c> that provides a format context.</param>
			/// <param name="culture">A <c>CultureInfo</c> object. If <see langword="null"/> is passed, the current culture is assumed. </param>
			/// <param name="value">The <c>Object</c> to convert.</param>
			/// <param name="destinationType">The <c>Type</c> to convert the value parameter to.</param>
			/// <returns>An <c>Object</c> that represents the converted value.</returns>
			[SecuritySafeCritical]
			public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
				if (destinationType != typeof(InstanceDescriptor))
					return base.ConvertTo(context, culture, value, destinationType);
				
				SRExtension extension = value as SRExtension;
				if (extension == null)
					throw new ArgumentException("The extension must be of type 'SRExtension'.");
				return new InstanceDescriptor(typeof(SRExtension).GetConstructor(new Type[] { typeof(string) }), new object[] { extension.Name });
			}

		}

		#endregion

		/////////////////////////////////////////////////////////////////////////////////////////////////////
		// OBJECT
		/////////////////////////////////////////////////////////////////////////////////////////////////////
		
		/// <summary>
		/// Creates an instance of the <c>SRExtension</c> class.
		/// </summary>
		public SRExtension() {}
			
		/// <summary>
		/// Creates an instance of the <c>SRExtension</c> class.
		/// </summary>
		/// <param name="name">The name of the string resource.</param>
		public SRExtension(string name) {
			if (name == null)
				throw new ArgumentNullException("name");

			// Initialize parameters
			this.name = name;
		}
		
		/////////////////////////////////////////////////////////////////////////////////////////////////////
		// PUBLIC PROCEDURES
		/////////////////////////////////////////////////////////////////////////////////////////////////////
		
		/// <summary>
		/// Gets or sets the name of the string resource.
		/// </summary>
		/// <value>The name of the string resource.</value>
		[ConstructorArgument("name")]
		public string Name {
			get {
				return name;
			}
			set {
				if (value == null)
					throw new ArgumentNullException("value");
				name = value;
			}
		}

		/// <summary>
		/// Returns the string resource based on the supplied name.
		/// </summary>
		/// <param name="serviceProvider">An object that can provide services for the markup extension.</param>
		/// <returns>The object value to set on the property where the extension is applied.</returns>
		public override object ProvideValue(IServiceProvider serviceProvider) {
			if (name == null)
				throw new ArgumentException("No string resource name was specified.");

			// Validate
			try {
				Enum.Parse(typeof(SRName), name);
			}
			catch (ArgumentException) {
				throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, "The string resource name '{0}' is not valid.  Please see the 'SRName' enumeration for the valid names.", name));
			}

			return SR.GetString(name);
		}

	}

}
